package com.mangix.http;

import com.mangix.core.MangixNode;
import com.mangix.utils.MangixUtils;
import org.json.simple.JSONValue;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * Created by Ahan on 2014/5/20.
 */
public class MangixObjectServlet extends HttpServlet {
    private MangixServer server;

    public MangixObjectServlet(MangixServer server) {
        this.server = server;
    }


    @Override
    protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String pathInfo = req.getPathInfo();
        String key;
        if (pathInfo != null) {
            key = pathInfo.substring(1);
        } else {
            resp.sendError(404);
            return;
        }
        MangixNode node = server.getNode();
        MangixNode successor;
        try {
            successor = node.findSuccessor(MangixUtils.hash(key, node.getConfig().getM()));
            if (successor == null) {
                resp.sendError(500, "Can not find the successor of " + key + " now.");
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            resp.sendError(500, e.getMessage());
            return;
        }
        try {
            Map meta = successor.getMeta(key);
            if (meta != null) {
                resp.setHeader(MangixHttpHeader.META, JSONValue.toJSONString(meta));
            } else {
                resp.sendError(404, "Key not found.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            resp.sendError(500, e.getMessage());
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String pathInfo = req.getPathInfo();
        String key = null;
        if (pathInfo != null)
            key = pathInfo.substring(1);
        else {
            resp.sendError(404);
            return;
        }
        MangixNode node = server.getNode();
        try {
            MangixNode successor = node.findSuccessor(MangixUtils.hash(key, server.getConfig().getM()));
            resp.sendRedirect("http://" + successor.getHostName() + ":" + successor.getPort() + "/direct/objects/" + key);
        } catch (Exception e) {
            e.printStackTrace();
            resp.sendError(500, e.getMessage());
        }
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String pathInfo = req.getPathInfo();
        if (pathInfo == null) {
            resp.sendError(404);
            return;
        }
        String key = pathInfo.substring(1);
        MangixNode localNode = server.getNode();
        AsyncContext context = null;
        try {
            MangixNode successor = localNode.findSuccessor(MangixUtils.hash(key, server.getConfig().getM()));
            int replicasNum = 1;
            if (req.getHeader(MangixHttpHeader.REPLICAS_NUM) != null) {
                replicasNum = Integer.parseInt(req.getHeader(MangixHttpHeader.REPLICAS_NUM));
            }
            context = req.startAsync();
            ServletInputStream in = req.getInputStream();
            in.setReadListener(new MangixObjectReadListener(in, context, successor.getHostName(), successor.getPort(), key, replicasNum, req.getContentLength()));
        } catch (Exception e) {
            e.printStackTrace();
            resp.sendError(500, e.getMessage());
            if (context != null) {
                context.complete();
            }
            return;
        }
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String pathInfo = req.getPathInfo();
        String key = null;
        if (pathInfo != null)
            key =  pathInfo.substring(1);
        else {
            resp.sendError(404);
            return;
        }
        MangixNode node = server.getNode();
        try {
            MangixNode successor = node.findSuccessor(MangixUtils.hash(key, server.getConfig().getM()));
            MangixHttpClient.delete("http://" + successor.getHostName() + ":" + successor.getPort() + "/direct/objects/" + key);
        } catch (Exception e) {
            e.printStackTrace();
            resp.sendError(500, e.getMessage());
        }
    }
}
